package cn.wdm.ymcc.service.impl;

import cn.wdm.ymcc.domain.Block;
import cn.wdm.ymcc.domain.MessageSms;
import cn.wdm.ymcc.domain.VerifycodeDto;
import cn.wdm.ymcc.exception.GloablException;
import cn.wdm.ymcc.service.IBlockService;
import cn.wdm.ymcc.service.IMessageSmsService;
import cn.wdm.ymcc.service.IVerifyCodeService;
import cn.wdm.ymcc.util.StrUtils;
import cn.wdm.ymcc.util.VerifyCodeUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IMessageSmsService messageSmsService;
    @Autowired
    private IBlockService iBlockService;

    @Override
    public String verifyCode(String key) {
        if (!StringUtils.hasLength(key)) {
            throw new GloablException("前端传的UUID不能为空");
        }
        //随机生成4位数
        String string = StrUtils.getRandomString(4);
        //将生成的数存入redis缓存中
        redisTemplate.opsForValue().set(key,string,5, TimeUnit.MINUTES);
        //将文字转为base64编码的字符串
        return VerifyCodeUtils.verifyCode(100,40,string);
    }
    /**
     *获取短信验证码，需要校验图形验证码
     * @param dto
     */
    @Override
    public void getSmsCode(VerifycodeDto dto) {
        String phone = dto.getMobile();//点段填写的电话号码
        String codeKey = dto.getImageCodeKey();//前端的图片存的的UUID
        String codeValue = dto.getImageCode();//前端输入框的图片验证码值
        //        1.参数非空校验
        if (StringUtils.isEmpty(phone)||StringUtils.isEmpty(codeKey)||StringUtils.isEmpty(codeValue)) {
            throw new GloablException("你输入的参数为空");
        }

       // @TODO 黑名单校验
        //获取当前操作人ip，判断有没有在黑名单中
        RequestAttributes requestAttributesTem = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest requestTem = ((ServletRequestAttributes) requestAttributesTem).getRequest();
        String ip = requestTem.getRemoteAddr();//获取IP地址
        //Block block=iBlockService.selectByPhone(phone);
        Wrapper<Block> tWrapper = new EntityWrapper();
        tWrapper.eq("phone",phone);  // where phone = 123123
        Block block = iBlockService.selectOne(tWrapper);
        //Block block=blockService.selectByIp(ip);
        if(block!=null){
            throw new GloablException("你被拉进黑名单啦！老铁！");
        }
//        2.图片验证码校验
//            2.1校验错误抛异常
//            2.2校验正确王下走
        //在redis中根据图片验证码的key，去获取图片验证码
        //图片验证码不区分大小写
        //获取图片验证码
        Object imgValue = redisTemplate.opsForValue().get(codeKey);
        //图片验证码不相等 抛异常
        if (!imgValue.toString().equalsIgnoreCase(codeValue)) {
            throw new GloablException("验证码输入错误！");
        }
//        3.电话号码是否注册过
        /*User user=userMapper.loadByPhone(phone);*/
//            3.1注册过 提示已经注册
      /*  if (user != null) {
            throw new GloablException("账户已经注册，请直接登录");
        }*/
//            3.2没有注册过继续往下走
//        4.发送短信逻辑
//            4.1根据手机号 拼接key，然后根据key获取曾将可能存在的短信验证码 register:1838
        String smsKey= "register" +phone;
        //查询redis中是否之前存在短信验证码
        Object smsValue = redisTemplate.opsForValue().get(smsKey);//9523:4684654946165
        if (smsValue!=null) {
            Long oldTime = Long.valueOf(smsValue.toString().split(":")[1]);
            //如果redis中的短信验证码不为空
            //1.判断获取时间是不是小于一分钟，如果小于一分钟说明跳过前端，直接访问接口。恶意攻击
            if (System.currentTimeMillis()-oldTime<6000) {
                throw new GloablException("就你攻击我是吧！");
            }
            //验证码
            //2.超过了一分钟获取验证码，就用之间的那个验证码，重新设置过期时间和时间戳
            String str = smsValue.toString().split(":")[0];
            String strTem=str+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + str + "。请在3分钟内使用！！");
        }else{
            //获取随机4位验证码
            String smsCode = StrUtils.getComplexRandomString(4);//9523
            String strTem=smsCode+":"+System.currentTimeMillis();//9523:468468486469866
            redisTemplate.opsForValue().set(smsKey,strTem,3,TimeUnit.MINUTES);
            System.out.println("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");

            //将发送短信的数据保存到数据库，可以做拉黑！！
            MessageSms messageSms = new MessageSms();
            messageSms.setPhone(phone);
            messageSms.setContent("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");
            messageSms.setSendTime(new Date());
            messageSms.setTitle("注册短信验证码");
            // 获取请求体 request
            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            messageSms.setIp(request.getRemoteAddr());//获取IP地址
            messageSmsService.insert(messageSms);
        }
//                4.1.1获取到了短信验证码 根据key在redis中获取value 有
//                    1.查看是否到一分钟 小于一分钟 抛出恶意攻击异常
//                                       大于一分钟，说明是再次申请了验证码 重新刷新key的过期时间，然后重新拼接时间错
//                4.1.2没有获取到短信验证码
//                    就生成验证码然后拼接新的时间戳
    }
}
